
/******************************************************************************
*@file  : app.c
*@brief : application
******************************************************************************/

#include "app.h" 


TIM_HandleTypeDef TIMx_Handler;  
       
  
#define CHANNEL_NUMBER  4  
#define CAPTURE_TIMES   4  

volatile uint16_t g_CaptureStart, g_CaptureEnd;       
volatile uint16_t g_CaptureData[4][4];      
volatile uint32_t g_CaptureTime;  
static uint32_t g_TimerClock; 
uint8_t g_CaptureChannel; 


#define BUZZER_OUTPUT_FREQ  100000  // 100K  

/******************************************************************************
*@brief:  TIM3 capture by channel 1 initiation, includes clock, gpio, capture channel. 
*@param:  None
*@return: None
******************************************************************************/
void TIMx_IC1_Init(void)  
{
	TIM_IC_InitTypeDef Tim_IC_Init_Para;
    GPIO_InitTypeDef TIM_GPIO_Init;   

    TIM_GPIO_Init.Drive = GPIO_DRIVE_LEVEL3;     
	
	TIMx_Handler.Instance = TIM3;
	TIMx_Handler.Init.ARRPreLoadEn = TIM_ARR_PRELOAD_ENABLE;       
	TIMx_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 
	TIMx_Handler.Init.CounterMode = TIM_COUNTERMODE_UP; 
	TIMx_Handler.Init.RepetitionCounter = 0;  
	TIMx_Handler.Init.Prescaler = 0;  
	TIMx_Handler.Init.Period = 0xFFFF;     // max period 
	
	HAL_TIMER_MSP_Init(&TIMx_Handler);         
	HAL_TIMER_Base_Init(&TIMx_Handler);       
	    
	Tim_IC_Init_Para.TIFilter = TIM_TI1_FILTER_LVL(0x08);    //  filter    
	Tim_IC_Init_Para.ICPolarity = TIM_SLAVE_CAPTURE_ACTIVE_FALLING;         
	Tim_IC_Init_Para.ICPrescaler = TIM_IC1_PRESCALER_1; 
	Tim_IC_Init_Para.ICSelection = TIM_ICSELECTION_DIRECTTI;     //TI1FP1->IC1, it is direct  
	HAL_TIMER_Capture_Config(TIMx_Handler.Instance, &Tim_IC_Init_Para,  TIM_CHANNEL_1);     
	    
	if(Tim_IC_Init_Para.ICSelection == TIM_ICSELECTION_DIRECTTI) 
    {                        
        TIM_GPIO_Init.Pin = GPIO_PIN_3;//TIM3_CH1 PB3-AF2   
        TIM_GPIO_Init.Mode = GPIO_MODE_AF_PP;          
        TIM_GPIO_Init.Pull = GPIO_NOPULL;    
        TIM_GPIO_Init.Alternate = GPIO_FUNCTION_2;         
        HAL_GPIO_Init(GPIOB, &TIM_GPIO_Init); 
        printfS("TIM3_CH1 PB3-AF2 \r\n");            
    }
    else if(Tim_IC_Init_Para.ICSelection == TIM_ICSELECTION_INDIRECTTI)
    {     
        TIM_GPIO_Init.Pin = GPIO_PIN_2;//TIM3_CH2 PA2-AF2   
        TIM_GPIO_Init.Mode = GPIO_MODE_AF_PP;          
        TIM_GPIO_Init.Pull = GPIO_NOPULL;    
        TIM_GPIO_Init.Alternate = GPIO_FUNCTION_2;         
        HAL_GPIO_Init(GPIOA, &TIM_GPIO_Init); 
        printfS("TIM3_CH2 PA2-AF2 \r\n");             
    }   
		 
} 


/******************************************************************************
*@brief:  start timer capture by channel 1
*@param:  None
*@return: None
******************************************************************************/
void TIMx_IC1_Capture(void)     
{
    uint16_t i, delta;    
    
    i = 0;        
    HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_1);   
    HAL_TIM_Capture_Start(TIMx_Handler.Instance, TIM_CHANNEL_1);   
    while(1)  
	{
	
        while (0 == (TIM3->SR & TIMER_SR_CC1IF)  );     		
		g_CaptureStart = TIM3->CCR1; 
        HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_1);   
            
        while (0 == (TIM3->SR & TIMER_SR_CC1IF)  );       		
        g_CaptureEnd = TIM3->CCR1; 
        delta = g_CaptureEnd-g_CaptureStart;  
        printfS("IC1 capture test, g_CaptureStart:%d, g_CaptureEnd:%d, Delta:%u\n", g_CaptureStart, g_CaptureEnd, delta);    
        printfS("Input frequency is %dHz\n", g_TimerClock/delta);   
        HAL_Delay(500+i);  // delay different period   
        i++;
        if (i > 1500) 
        {
            i = 0; 
        }
        HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_1);         		
	}
}

/******************************************************************************
*@brief:  start timer capture by channel 1, read data in interrupt servic 
*@param:  None
*@return: None
******************************************************************************/
void TIMx_IC1_Capture_IT(void)     
{
    uint16_t delta[CAPTURE_TIMES-1];         
    uint32_t i;     
    
    g_CaptureTime = 0;        
    for(i = 0; i < (CAPTURE_TIMES-1); i++)  
    {
        delta[i] = 0;    
    }      
    
    HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_1); 
    NVIC_ClearPendingIRQ(TIM3_IRQn);     
    NVIC_EnableIRQ(TIM3_IRQn);     
    HAL_TIM_ENABLE_IT(&TIMx_Handler, TIM_IT_CC1);    
    HAL_TIM_Capture_Start(TIMx_Handler.Instance, TIM_CHANNEL_1);     
    
    while(1)
	{
	
        if (g_CaptureTime >= CAPTURE_TIMES)  
        {
            HAL_TIM_DISABLE_IT(&TIMx_Handler, TIM_IT_CC1);   
            HAL_TIM_Capture_Stop(TIMx_Handler.Instance, TIM_CHANNEL_1);    
            
            for(i = 0; i < (CAPTURE_TIMES-1); i++)  
            {
               delta[i] = g_CaptureData[TIM_CHANNEL_1][i+1] - g_CaptureData[TIM_CHANNEL_1][i];    
            }
            for(i = 0; i < (CAPTURE_TIMES-1); i++)  
            {
                 printfS("IC1 capture test, i=%d, Delta[i]:%u\n", i, delta[i]);  
                 printfS("Input frequency is %dHz\n", g_TimerClock/delta[i]);  
            }
            
            HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_1);   
            break;   
        }            		
	}
}  


/******************************************************************************
*@brief:  timer capture by channel 2 initiation, includes clock, gpio, capture channel.  
*@param:  None
*@return: None
******************************************************************************/
void TIMx_IC2_Init(void)  
{ 
	TIM_IC_InitTypeDef Tim_IC_Init_Para;
    GPIO_InitTypeDef TIM_GPIO_Init;   

    TIM_GPIO_Init.Drive = GPIO_DRIVE_LEVEL3;     
	
	TIMx_Handler.Instance = TIM3;
	TIMx_Handler.Init.ARRPreLoadEn = TIM_ARR_PRELOAD_ENABLE;       
	TIMx_Handler.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; 
	TIMx_Handler.Init.CounterMode = TIM_COUNTERMODE_UP; 
	TIMx_Handler.Init.RepetitionCounter = 0;  
	TIMx_Handler.Init.Prescaler = 0;  
	TIMx_Handler.Init.Period = 0xFFFF;     // max period 
	
	HAL_TIMER_MSP_Init(&TIMx_Handler);         
	HAL_TIMER_Base_Init(&TIMx_Handler);       
	    
	Tim_IC_Init_Para.TIFilter = TIM_TI2_FILTER_LVL(0x08);    // filter configuration     
	Tim_IC_Init_Para.ICPolarity = TIM_SLAVE_CAPTURE_ACTIVE_FALLING;         
	Tim_IC_Init_Para.ICPrescaler = TIM_IC2_PRESCALER_1; 
	Tim_IC_Init_Para.ICSelection = TIM_ICSELECTION_DIRECTTI;// TI1FP2->IC2, it is direct way   	 
	HAL_TIMER_Capture_Config(TIMx_Handler.Instance, &Tim_IC_Init_Para,  TIM_CHANNEL_2);     

	if(Tim_IC_Init_Para.ICSelection == TIM_ICSELECTION_DIRECTTI) 
    {             
        TIM_GPIO_Init.Pin = GPIO_PIN_2;//TIM3_CH2 PA2-AF2   
        TIM_GPIO_Init.Mode = GPIO_MODE_AF_PP;          
        TIM_GPIO_Init.Pull = GPIO_NOPULL;    
        TIM_GPIO_Init.Alternate = GPIO_FUNCTION_2;         
        HAL_GPIO_Init(GPIOA, &TIM_GPIO_Init);
        printfS("TIM3_CH2 PA2-AF2  \r\n");       
    }
    else if(Tim_IC_Init_Para.ICSelection == TIM_ICSELECTION_INDIRECTTI)
    {
        TIM_GPIO_Init.Pin = GPIO_PIN_3;//TIM3_CH1 PB3-AF2   
        TIM_GPIO_Init.Mode = GPIO_MODE_AF_PP;          
        TIM_GPIO_Init.Pull = GPIO_NOPULL;    
        TIM_GPIO_Init.Alternate = GPIO_FUNCTION_2;         
        HAL_GPIO_Init(GPIOB, &TIM_GPIO_Init);
        printfS("TIM3_CH1 PB3-AF2  \r\n");      
    }
} 

/******************************************************************************
*@brief:  start timer capture by channel 2   
*@param:  None
*@return: None
******************************************************************************/
void TIMx_IC2_Capture(void)     
{
    uint16_t i, delta;   
    
    i = 0;  
    
    HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_2);    
    HAL_TIM_Capture_Start(TIM3, TIM_CHANNEL_2);   
    while(1)  
	{
	
        while (0 == (TIM3->SR & TIMER_SR_CC2IF)  );     		
		g_CaptureStart = TIM3->CCR2; 
        HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_2);      
            
        while (0 == (TIM3->SR & TIMER_SR_CC2IF)  );     		
        g_CaptureEnd = TIM3->CCR2; 
        
        delta = g_CaptureEnd-g_CaptureStart;  
        printfS("IC2 Capture test, g_CaptureStart:%d, g_CaptureEnd:%d, Delta:%u\n", g_CaptureStart, g_CaptureEnd, delta);  
        printfS("Input frequency is %dHz\n", g_TimerClock/delta); 
        HAL_Delay(500+i);  // delay different period   
        i++;
        if (i > 1500) 
        {
            i = 0; 
        }
        HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_2);       		
	}
}  

/******************************************************************************
*@brief:  start timer capture by channel 2, read data in interrupt servic   
*@param:  None
*@return: None
******************************************************************************/ 
void TIMx_IC2_Capture_IT(void)     
{
    uint16_t delta[CAPTURE_TIMES-1];         
    uint32_t i;     
    
    g_CaptureTime = 0;        
    for(i = 0; i < (CAPTURE_TIMES-1); i++)  
    {
        delta[i] = 0;    
    }      
    
    HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_2);
    NVIC_ClearPendingIRQ(TIM3_IRQn);     
    NVIC_EnableIRQ(TIM3_IRQn);       
    HAL_TIM_ENABLE_IT(&TIMx_Handler, TIM_IT_CC2);    
    HAL_TIM_Capture_Start(TIMx_Handler.Instance, TIM_CHANNEL_2);     
    
    while(1)
	{
	
        if (g_CaptureTime >= CAPTURE_TIMES)  
        {
            HAL_TIM_DISABLE_IT(&TIMx_Handler, TIM_IT_CC2);   
            HAL_TIM_Capture_Stop(TIMx_Handler.Instance, TIM_CHANNEL_2);    
            
            for(i = 0; i < (CAPTURE_TIMES-1); i++)  
            {
               delta[i] = g_CaptureData[TIM_CHANNEL_2][i+1] - g_CaptureData[TIM_CHANNEL_2][i];    
            }
            for(i = 0; i < (CAPTURE_TIMES-1); i++)  
            {
                 printfS("IC2 capture test, i=%d, Delta[i]:%u\n", i, delta[i]);  
                 printfS("Input frequency is %dHz\n", g_TimerClock/delta[i]);   
            }
            
            HAL_TIMER_Clear_Capture_Flag(&TIMx_Handler, TIM_CHANNEL_2);   
            break;   
        }            		
	}
} 

/******************************************************************************
*@brief:  set buzzer divide factor 
*@param:  clk: Buzzer Clock source
*@param:  div: div factor, if div = 80 then output buzzer freq=HCLK/80   
*@param:  enable: FUNC_DISABLE and FUNC_ENABLE      
*@return: None
******************************************************************************/
void Set_Buzzer_Divider(uint8_t clk, uint32_t div, uint8_t enable)  
{      
    if (1 == enable)
    {
        RCC->CLKOCR &= (~0x0F);
        RCC->CLKOCR |= (clk & 0x0F);
        RCC->CLKOCR = (RCC->CLKOCR & (~(0x1FFFFU << 5) ) ) | (div << 5);      
        RCC->CLKOCR |= BIT23;  
    }
    else
    {
        RCC->CLKOCR &= (~BIT23);   
    }
} 

/******************************************************************************
*@brief:  Timer input capture test   
*@param:  capture_channel: TIM_CHANNEL_1, TIM_CHANNEL_2
*@return: None
******************************************************************************/
void Timer_Capture_Test(uint32_t capture_channel)    
{
//    #define READ_CAPTURE_DATA_BY_INTERRUPT
    
    g_CaptureChannel = capture_channel;
    
    printfS("Timer3 Channel_%d Input capture:\r\n", (g_CaptureChannel + 1));
    
    Set_Buzzer_Divider(0, (HAL_RCC_GetHCLKFreq()/BUZZER_OUTPUT_FREQ) - 1, 1);

    g_TimerClock = HAL_RCC_GetPCLK1Freq();
    
    if (HAL_RCC_GetHCLKFreq() != g_TimerClock)  // if hclk/pclk != 1, then TIMx clk = pclk * 2  
    {
        g_TimerClock =  g_TimerClock << 1;    
    }
 
	switch(g_CaptureChannel)
    {
        case TIM_CHANNEL_1:  
        TIMx_IC1_Init();
#ifndef READ_CAPTURE_DATA_BY_INTERRUPT           
        TIMx_IC1_Capture();      
#else  
        TIMx_IC1_Capture_IT();         
#endif                 
        break;  
        
        case TIM_CHANNEL_2:  
        TIMx_IC2_Init();
#ifndef READ_CAPTURE_DATA_BY_INTERRUPT          
        TIMx_IC2_Capture();  
#else  
        TIMx_IC2_Capture_IT();       
#endif           
        break;  
           
        default: 
        printfS("Application not supported \n");   
        break;  
    }

}


/******************************************************************************
*@brief:  APP_Test.
*@param:  None
*@return: None
******************************************************************************/
void APP_Test(void)
{
    Timer_Capture_Test(TIM_CHANNEL_2);
}



